﻿#pragma once

#include <QBitArray>
#include <iostream>
#include <QList>
#include <list>
#include <functional>
#include <QFile>
#include <QFileInfo>
#include <PinParser.h>
#include <XLDocument.hpp>

#include "exprvalue.h"
#include "symnode.h"
#include "antlr4-runtime.h"



//#define PIN_DEBUG 1

//#define PIN_MEM_REF 1 

#ifdef PIN_MEM_REF
extern int newTimes;
extern int freeTimes;

void newTime(int v =1);
void subTime();
#endif

extern bool s_isExcep;

#define ExprValue_ ExprValue

struct STRUCT_VALUE_DATA_;
class ExprValue;

void AbortException(QString& errmsg);

//减少计算，为0则删除
int subListMapRefNum(void* pAddr);


//加入计数，没有则增加
int addListMapRefNum(void* pAddr);

QByteArray lexBytesToEscapeBytes(QByteArray& src);
QByteArray lexRawBytesToEscapeBytes(QByteArray& src);

//根据名称获取类型
int getVarTypeByName(std::string& name);
QString getVarTypeNameByName(std::string& name, antlr4::ParserRuleContext* ctx=nullptr);
QString getExpeTypeValue(int type,ExprValue *pExpr=nullptr);

bool isGloablVarAlreadyExist(std::string name);
void destoryPinFunSysTable();
void destoryPinSymTable();
void destoryPinRunStatus();

#ifdef NDD_PIN_FUN
#else
//为了避免路径中\\不一样导致的查找不到问题，进行统一替换
QString getRegularFilePath(QString& path);
#endif

typedef struct pin_status_info_ {
    int status;
    int data;
    pin_status_info_()
    {
        status = -1;
        data = -1;
    }
}pin_status_info;

typedef struct FUN_SYM_INFO_ {
    std::string* funBlock; //函数体
    antlr4::ParserRuleContext* pBlock;
    int funNameLineNum; //行号,函数名称的行号。
    int blockLineNum;//块开始的行号。
    std::string funDec; //函数声明

    std::vector<std::string>* paraList; // 函数参数。没有则为空
    std::vector<std::string>* retList; // 返回参数，没有则为空
    FUN_SYM_INFO_() :funBlock(nullptr), paraList(nullptr),retList(nullptr),pBlock(nullptr)
    {
    }
    void destory()
    {
        if(funBlock != nullptr)
        {
            delete funBlock;
            funBlock = nullptr;
#ifdef PIN_MEM_REF
            freeTimes++;
#endif
        }
        if(paraList!=nullptr)
        {
            delete paraList;
            paraList = nullptr;
#ifdef PIN_MEM_REF
            freeTimes++;
#endif
        }
        if(retList!=nullptr)
        {
            delete retList;
            retList = nullptr;
#ifdef PIN_MEM_REF
            freeTimes++;
#endif
        }
    }
}FUN_SYM_INFO;

std::unordered_map<std::string, FUN_SYM_INFO*>* getPinFunSysTable();

void initListMapRefNum();
void destoryListMapRefNum();
int getListMapRefNum(void* pAddr);
SymNode* getGloablVar(std::string name);

enum PIN_RUN_STATUS{
    NOTHING_STATUS=-1, //啥也没有，一般不出现
    INTO_GLOBAL,
    DEFVAR_STATUS,//定义变量中
    GLOBAL_DEFVAR_STATUS,//全局定义变量中
    INTO_FUN_FIRST_BLOCK_SCOPE,//调用函数时，进入函数的第一个作用域块。
    FUNCTION_RET,//遇到函数返回语句。

    RETURN_WITH_FUNCTION_RESULT_NEED_RETVALUE,//以函数结果的方式返回,而且需要调用函数的返回值
    RETURN_WITH_FUNCTION_RESULT_IGNORE_RETVUALE,//以函数结果的方式返回,但是忽略调用函数的返回值
    INTO_BREAK,//遇到break
    INTO_CONTINUE,//遇到contiune
    CALL_BACK_FUN_NEED_RETVALUE,// fanzhi hd_xx 的形式，即以回调函数结构的方式返回，而且需要调用函数的返回值。已经作废
    MULTI_CPP_FUN_CALL,//是否是多级调用
    LAST_ERROR_LINE_NUM,//最后崩溃时，错误语句在函数中的行号偏移，是从block开始计算的。
};



int getPinRunStatus();
pin_status_info getPinRunStatusData();

void pushStatus(int v);
void pushStatus(pin_status_info& v);
void popStatus();

int getLastFunStartLineNum(int mode=0);

//插入函数名称和函数体到函数符号表
FUN_SYM_INFO* addFunBlock(std::string name, std::string& block, std::vector<std::string>& paraList,std::vector<std::string>& retList);

//根据函数名称查找函数体，存在返回，否则返回 nullptr
FUN_SYM_INFO* findFunBlock(std::string name);

//最近作用域是否存在局部变量
bool isLoaclVarAlreadyExist(std::string name);


//删除当前作用域
bool deleteCurScope();

void deleteCurScopeVar(SymNode* pSym);

//删除当前函数
bool deleteCurFunction();

//当前的函数调用者是否关注返回值。
bool isFunNeedReturnValue();

//设置当前调用函数的返回值
bool setcurFunReturnValue(void* pData);

QList<SymNode*>* getcurFunReturnValue();

//当前是否在循环中
bool isInFor();

//当前函数的返回参数列表
std::vector<std::string>* curFunRetPara(std::string* funName=nullptr);

std::string getCurFunName();

//退出for循环的作用域
bool deleteCurForScope();



enum SymNodeType {
	UNUSE_SYM = -1,
    //
    /*EXPR_INT = 0,
    EXPR_INT64,
    EXPR_FLOAT,
    //EXPR_DOUBLE,
    EXPR_POINT,
    EXPR_STRING,
*/
    BASE_TYPE=50,
    ERR_INFO,//为了方便定位，在一些关键语句中，加入该类型的消息，本质是个字符串。
    TIPS_INFO,//和ERR_INFO类似，单纯的字符串。
    HD_TO_HS_INFO,//回调函数映射为全局函数的这么一个表。

    VAR_SYM = 100, //前面的100留给变量，继续做变量的细分类型。这个本身不使用，是变量类型的最大值。小于VAR_SYM的都是变量类型
    FUN_SYM = 101,//函数名称
	SCOPE_SYM,//作用域
    FOR_SCOPE,//for作用域
    NEED_FUN_RET_VALUE,//需要返回值。如果函数需要返回值，则设置vint为该值。

};

//增加一个新作用域
void addNewScope(int type = SCOPE_SYM);

typedef struct ERR_DATA_INFO_{
    int lineNum;
    std::string lineContens;
}ERR_DATA_INFO;

typedef struct ExprValue_2{
    int type; //ExprValueType
    union {
        bool vbool;
        int vint;
        qint64 vint64;
        double vfloat;
        //double vdouble;
        void* vpoint;
    }value;
}ExprValue2;


int addListMapRefNum(SymNode* pAddr);
int subListMapRefNum(SymNode* pExpr);

int addListMapRefNum(ExprValue& pExpr);
int subListMapRefNum(ExprValue& pExpr);

void initVarGlobalSymTable();
void destoryVarGlobalSymTable();

//表达式返回值
//20250128 明确一下类型的内存拷贝问题。字符串需要做深入拷贝，释放的时候要释放。
//基本类型（不包括字符串），不存在深拷贝问题，直接是单独对象。
//结构体做赋值左值的时候，需要深拷贝一份右值内存，避免两个结构体指向同一份空间。
//字符串做赋值左值时，需要做深拷贝一份右值内存
//列表和字典做赋值左值时，不做深拷贝，而是引用右值内存


enum STRUCT_VALUE_TYPE_ID{
    Struct_Unkonwn_ID = 0,
    XLWorksheet_Struct_ID = EXPR_MAX_END+1,//不与既有的报名冲突。
    //PString_Struct_Id,
    //PChar_Struct_Id,
#ifdef NDD_PIN_FUN
    NddMainWin_Struct_ID,
    Editor_Struct_ID,
#endif
    REGEXP_Struct_ID,
    REGMATCH_Struct_ID,
    REGMATCH_ITER_Struct_ID,
};

int getStructIdByDescName(std::string& name);


//结构体的值。规定结构体不能嵌套，结构体中的值，只能是基本变量。时间和文件，文件有点例外，文件是引用管理的，这是后面加入的。
typedef struct STRUCT_VALUE_DATA_{
    void* pValue; //真正的值 以std::vector<ExprValue*>的方式在这里挂着。
    //void* pCppObj;//对应的cpp中的对象，在上层中对pin语言不可见，但是在下层，需要使用该对象做转接操作。
    std::any pCppObj; //这个变量是不需要释放的，可以理解为都是值拷贝。就算是指针，也是引用，不需要自己释放的那种。
    std::string structType;//结构体类型
    int structTypeId; //每个类型给分配一个唯一的ID //如果是非cpp底层的对象，则为Struct_Unkonwn_ID。凡是cpp对象，都有对应的值。

    STRUCT_VALUE_DATA_():pValue(nullptr),structTypeId(Struct_Unkonwn_ID)
    {

    }
    void destory()
    {
        std::vector<ExprValue*>* exprVec = (std::vector<ExprValue*>*)(pValue);
        if (exprVec != nullptr)
        {
            for (int i = 0, c = exprVec->size(); i < c; ++i)
            {
                exprVec->operator [](i)->freeMem();
                delete exprVec->operator [](i);
#ifdef PIN_MEM_REF
                freeTimes++;
#endif
            }
            delete exprVec;
#ifdef PIN_MEM_REF
            freeTimes++;
#endif
        }
            pValue = nullptr;
    }
    /*~STRUCT_VALUE_DATA_()
    {

    }*/
    STRUCT_VALUE_DATA_(const STRUCT_VALUE_DATA_& other) = delete;
    STRUCT_VALUE_DATA_& operator=(const STRUCT_VALUE_DATA_& other) = delete;

    //手动写一个深拷贝的函数，严格规范调用的时机，避免紊乱
    //结构体的值访问，使用深拷贝，避免对原始值的修改
    STRUCT_VALUE_DATA_* deepCopy()
    {
        STRUCT_VALUE_DATA_* pSrc = this;

        STRUCT_VALUE_DATA_* pNew = new STRUCT_VALUE_DATA_();
		#ifdef PIN_MEM_REF
            newTime();
#endif
        pNew->structType = pSrc->structType;
        pNew->pCppObj = pSrc->pCppObj; //这里后续要特别注意，最好不能是指针，因为如果存在指针，那就是浅拷贝了。可能std::any本身也有该限制。
        pNew->structTypeId = pSrc->structTypeId;

        if (pSrc->pValue != nullptr)
        {
            std::vector<ExprValue*>* pVec = (std::vector<ExprValue*>*)pSrc->pValue;

            std::vector<ExprValue*>* pNewVec = new std::vector<ExprValue*>(pVec->size());
#ifdef PIN_MEM_REF
            newTime();
#endif
            pNew->pValue = pNewVec;

            for (int i = 0, c = pVec->size(); i < c; ++i)
            {
                //这里要调用深拷贝等于函数。主要是string内存时的管理。
                //由于结构体不嵌套，这里ExprValue 返回的都是基本类型。包括时间和文件
                (*pNewVec)[i] = pVec->at(i)->deepCopy2();
            }
        }

        return pNew;
    }

}STRUCT_VALUE_DATA;

typedef struct EXCEL_VALUE_DATA_ {
    OpenXLSX::XLDocument* pDoc;
    //OpenXLSX::XLWorkbook workBook;
    std::string excelFileName;

    EXCEL_VALUE_DATA_() :pDoc(nullptr)
    {

    }
    void destory()
    {
        if (pDoc != nullptr)
        {
            if (pDoc->isOpen())
            {
                //20250422 发现有异常时，保存excel可能崩溃。
                if (!s_isExcep)
                {
                pDoc->save();
                }
                pDoc->close();
            }
            delete pDoc;
            pDoc = nullptr;
#ifdef PIN_MEM_REF
            freeTimes++;
#endif
        }
    }

}EXCEL_VALUE_DATA;

typedef struct FILE_VALUE_DATA_{
    QFile* pFile; //只有在文件打开的时候，才初始化pFile字段
    QFileInfo* pFileInfo;

    FILE_VALUE_DATA_():pFile(nullptr),pFileInfo(nullptr)
    {

    }

    void destory()
    {

        if(pFileInfo != nullptr)
        {
            delete pFileInfo;
            pFileInfo = nullptr;
#ifdef PIN_MEM_REF
            freeTimes++;
#endif
        }

        if(pFile != nullptr)
        {
            if(pFile->isOpen())
            {
                pFile->close();
            }
            delete pFile;
            pFile = nullptr;
#ifdef PIN_MEM_REF
            freeTimes++;
#endif
        }
    }
}FILE_VALUE_DATA;

//成员函数信息
typedef struct MEM_FUN_INFO_{
    std::string objName;//对象名称
    std::string funName;//函数名称
    MEM_FUN_INFO_(std::string obj, std::string fname):objName(obj),funName(fname)
    {

    }
}MEM_FUN_INFO;

//普通函数不需要，只需要函数名称即可



QList<SymNode*>* getPinSymTable();

//打印当前调用栈
void printStackInfo();

//从变量的名称找到符号，只查找变量。
SymNode* getVarFromSymTable(std::string name, antlr4::ParserRuleContext* ctx = nullptr);
void insertGlobalSymTable(std::string& name, SymNode* pSym);

SymNode* getVarFromGlobalSymTable(std::string name, antlr4::ParserRuleContext* ctx = nullptr,int isStruct=0);
bool isGlobalSymExist(std::string &name);
bool isStructDescExist(const std::string &name);

QString getCurFunQSName();

SymNode* getCurFunSym();
//bool funArgRefNoExistThenAdd(ExprValue& expr);

typedef struct Cpp_Fun_Info{
    //std::string funName;
    std::vector<int> paraVec; //参数的类型，后续要做检查
}Cpp_Fun_Info;

QList<ExprValue*>* getFunCallStack();
void initFunCallStack();
void destoryFunCallStack();

#define curStatement QString::fromStdString(ctx->getText())
#define QStr(x) (QString::fromStdString(x))


QString getSrcCodeState(antlr4::ParserRuleContext* ctx);
QString getSrcCodeStateOneline(antlr4::ParserRuleContext* ctx);
#define curSrcStatement getSrcCodeState(ctx)
#define curOnelineSrcStatement getSrcCodeStateOneline(ctx)

int getCurLineNum(antlr4::ParserRuleContext* ctx);
int getCurLineNum(PinParser::RealCallFunContext* & ctx);

int getGloblCurlineNum(antlr4::ParserRuleContext* ctx);

#define curLine getCurLineNum(ctx)

#define globalCurLine getGloblCurlineNum(ctx)

bool isKeyWordTypeVar(std::string name);
std::string getTypeDescName(int type,ExprValue *pExpr=nullptr);

void initStructDescIdMap();
void destoryStructDescIdMap();

enum CODE_ID {
    UNKOWN = -2,
    ANSI = -1,
    UTF8_NOBOM,//如果是这种，其实需要确定到底椒UTF8 还是ANSI
    UTF8_BOM, //UTF8_WITH BOM
    UNICODE_LE,
    UNICODE_BE,
    GBK,
    //增加国际化的几种语言
    EUC_JP,//日本鬼子
    Shift_JIS,//日文另外一种
    EUC_KR,//韩国
    KOI8_R,//俄罗斯
    TSCII,//泰国
    TIS_620,//泰文
    BIG5,//繁体中文
    UNICODE_LE_NOBOM,
    WINDOWS1250,//win1250 20230721新增
    IBM866,//20230724 新增。qt没有865，只有866
    CODE_END //最后一个标志,在UI上是显示一个UNKNOWN，这是一个特殊
};

QByteArray getQtCodecNameById(int id);
int checkCodeTextEncode(const uchar* pText, int length, QByteArray& outUtf8Code);

#define QDIR_WALK_BottomUp 0x8000 //自底向上的遍历
